from flask import request,jsonify,g
from app.extensions import cache
from flask_restful import abort
from app.models import User


def random_string(length=32): # 生成32位随机字符串，原本是为了生成随机文件名，用于保存上传的头像，所以默认32位
    import random
    string='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
    return ''.join(random.choice(string) for i in range(length))


def send_verification_code(phone): # 复制的blog项目的user.py，取消了是否已注册的判断(登录时未注册就自动注册)，phone由从request获取改为由参数传入，将flag改为status(其他地方也用的status，为了前端统一接收)
    if request.headers.get("X-Requested-With") == "XMLHttpRequest": # 说明是Ajax请求，详细看verify_phone路由的注释
        # 获取发送的Ajax请求中的字典的值，字典中键是phone
        # phone=request.args.get('phone') # 使用GET发送Ajax请求时这样获取字典的值。这里是获取name为phone的表单的输入框的值，笔记在01-Hello World搜request.args
        # phone=request.form['phone'] # 使用POST发送Ajax请求时这样获取字典的值
        # 无论get还是post参数，都能通过request.values.get('')获取
        # u=User.query.filter(User.phone==phone,User.is_deleted==False).first()
        # if u:
            # session[phone]='123456' # 将验证码与手机号绑定，防止登录时用当前手机号收到的验证码，和另外一个手机号进行登录。登录成功后要立即删除这个session，原因在删除处。session在一个文件内是全局的，其他地方可以直接访问。相关链接(不是来自这里)https://www.v2ex.com/t/349677
        cache.set(phone,'123456',timeout=300) # 第三个参数是过期时间，单位秒。原来的session保存手机号与验证码的键值对，现在将它放在redis缓存中。点击创建cache处的Cache查看支持的方法，在源码的@property处。也可以看https://flask-caching.readthedocs.io/en/latest/api.html#cache-api
            # 定义status为200表示验证码发送成功；为400表示该号码未注册，验证码未发送
            # return jsonify(status=200,message='验证码发送成功') # 需向"前端里向这里发来Ajax请求的地方"返回json格式，可以直接返回{key:value}，也可以用jsonify()，它会将传入的参数自动转为json格式
        return jsonify(status=200, message='验证码发送成功，5分钟内有效') # 上一行是用session时用
        # else:
            # return jsonify(status=400,message='该号码未注册，验证码未发送')


def check_user():
    auth=request.headers.get('Authorization') # 登录后的每条请求，请求头中都有Authorization，即token。postman的Authorization的Type要为No Auth，否则会跟Headers中的Authorization冲突，导致获取不到正确的token
    if not auth:
        abort(401,error='请先登录') # 第一个参数是状态码，第二个参数是要传的消息，可以不用error，可以用其他词
    mobile=cache.get(auth)
    if not mobile:
        abort(401,error='无效的令牌')
    u=User.query.filter(User.phone==mobile).first()
    if not u:
        abort(401,error='该用户不存在或已被删除')
    g.user=u


def login_required(func): # 自定义装饰器，被装饰的函数，需登录才能访问。也可以用flask_httpauth的HTTPBasicAuth，在第10个项目中
    def wrapper(*args,**kwargs):
        check_user()
        return func(*args,**kwargs)
    return wrapper